﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Scripting;
using Microsoft.Scripting.Ast;
using Microsoft.Scripting.Utils;

using Scala.Compiler.Binding;

namespace Scala.Compiler.Ast
{
    public class ModuleDefStatement:Statement
    {
        private readonly string _name;
        private int _headerIndex;
        private Statement _body;
        private readonly Expression[] _bases;
        private ScalaType _scalaType;

        private static int _classId;

        public ModuleDefStatement(string name, Expression[] bases, Statement body)
        {
            ContractUtils.RequiresNotNull(body, "body");
            ContractUtils.RequiresNotNullItems(bases, "bases");

            _name = name;
            Scope = new ScalaScope(name);
            Scope.IsModule = true;
            _bases = bases;
            _body = body;
        }

        public ScalaType ScalaType
        {
            get
            {
                if (_scalaType == null) return new ScalaType(Name, this);
                else return _scalaType;
            }
            set
            {
                _scalaType = value;
            }
        }
        public SourceLocation Header { get { return GlobalParent.IndexToLocation(_headerIndex); } }
        public int HeaderIndex
        {
            get { return _headerIndex; }
            set { _headerIndex = value; }
        }

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public IList<Expression> Bases
        {
            get { return _bases; }
        }

        public Statement Body { get { return _body; } }

        public override void Walk(ScalaWalker walker)
        {
            if (walker.Walk(this))
            {
                if (_bases != null)
                {
                    foreach (Expression b in _bases)
                    {
                        b.Walk(walker);
                    }
                }
                if (_body != null)
                {
                    _body.Walk(walker);
                }
            }
            walker.PostWalk(this);
        }

        public override Microsoft.Scripting.Ast.Expression Reduce()
        {
            IList<Microsoft.Scripting.Ast.Expression> constrBody = new List<Microsoft.Scripting.Ast.Expression>();
            foreach (var stat in ScalaType.GetContructorBody())
            {
                constrBody.Add(stat.Reduce());
            }
            foreach (var func in Scope.Functions)
            {
                if (!func.Value.IsConstructor)
                    func.Value.DefStatement.Reduce();
                //Expression.Lambda(Expression.Block(func.Value.DefStatement.Reduce())).CompileToMethod(func.Value.MethodBuilder);
            }
            Expression.Lambda(Expression.Block(constrBody)).CompileToMethod(ScalaType.GetConstructor());

            //foreach (var meth in ScalaType.ScalaScope.Functions)
            //{
            //    if(!meth.Value.IsConstructor)
            //    Expression.Lambda(Expression.Block(meth.Value.DefStatement.Body.Reduce())).CompileToMethod(meth.Value.MethodBuilder);
            //}

            ScalaType.TypeBuilder.CreateType();
            return Expression.Empty();
        }

        public object[] GetBases()
        {
            return _bases;
        }
    }
}
